package cn.com.support.utils;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.time.DateUtils;

import cn.com.commons.utils.StringUtil;

/**
 * 
 * 模板工具类
 * 
 * @since 2012-3-21 下午11:52:11
 * @version 1.0
 * @author Microbun
 * 
 */
public class TemplateUtils {
	/**
	 * 封装开始结束时间
	 * 
	 * @param map
	 * @param request
	 */
	public static void wappedStartAndEndTime(Map<Object, Object> map,
			ServletRequest request) {
		try {
			String startTime = request.getParameter("startTime");
			String endTime = request.getParameter("endTime");
			if (StringUtil.isNotBlank(startTime)) {
				map.put("startTime",
						DateUtils.parseDate(startTime, "yyyy-MM-dd"));
			}
			if (StringUtil.isNotBlank(endTime)) {
				map.put("endTime", DateUtils.parseDate(endTime, "yyyy-MM-dd"));
			}
		} catch (ParseException e) {
			// e.printStackTrace();
		}
	}

	/**
	 * 从request中获取指定类型的参数,如果参数没有值则给一个默认值
	 * 
	 * @param requiredType
	 *            参数类型
	 * @param request
	 *            请求对象
	 * @param name
	 *            参数名称
	 * @param defValue
	 *            默认值
	 * @return
	 */
	public static <T> T getParam(Class<T> requiredType, ServletRequest request,
			String name, T defValue) {
		T value = getParam(requiredType, request, name);
		if (value == null) {
			value = defValue;
		}
		return value;
	}

	/**
	 * 从request中获取指定类型的参数，如果无法转换为指定类型着返回null
	 * 
	 * @param requiredType
	 *            参数类型
	 * @param request
	 *            请求对象
	 * @param name
	 *            参数名称
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getParam(Class<T> requiredType, ServletRequest request,
			String name) {
		String value = request.getParameter(name);
		T values = (T) convertToBaseType(value, requiredType);
		return values;
	}

	/**
	 * 从request中获取指定类型的数组参数,如果参数没有值则给一个默认值
	 * 
	 * @param requiredType
	 *            参数类型
	 * @param request
	 *            请求对象
	 * @param name
	 *            参数名称
	 * @param defValues
	 *            默认值
	 * @return
	 */
	public static <T> T[] getParams(Class<T> requiredType,
			ServletRequest request, String name, T[] defValues) {
		T[] values = getParams(requiredType, request, name);
		if (values == null) {
			values = defValues;
		}
		return values;
	}

	/**
	 * 从request中获取指定类型的数组参数,如果无法转换为指定类型，或参数不存在则返回null
	 * 
	 * @param requiredType
	 *            参数类型
	 * @param request
	 *            请求对象
	 * @param name
	 *            参数名称
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] getParams(Class<T> requiredType,
			ServletRequest request, String name) {
		String[] values = request.getParameterValues(name + "[]");
		if (values == null) {
			String value = request.getParameter(name);
			if (value == null) {
				return null;
			}
			values = new String[] { request.getParameter(name) };
		}
		T[] a = (T[]) Array.newInstance(requiredType, values.length);
		for (int i = 0; i < values.length; i++) {
			try {
				a[i] = (T) convertToBaseType(values[i], requiredType);
			} catch (Exception e) {
				return null;
			}
		}
		return a;
	}

	/**
	 * 将{@link ServletRequest}
	 * 中的参数构造成一个包含<strong>Bean</strong>属性的<strong>Map</strong> 对象。</br>
	 * <strong>Map</strong> 中的key对应Bean的属性，如果<strong>Bean</strong>属性是基本封装数据类型
	 * ，则value的类型和<strong>Bean</strong> 的类型是一致的。
	 * <p>
	 * 
	 * @param request
	 *            如果为<code>null</code>，则返回一个空的<strong>Map</strong>
	 * @param clazz
	 *            Bean的类型,如果为<code>null</code>，则返回一个空的<strong>Map</strong>
	 * @return
	 */
	public static Map<Object, Object> bulidBeanMap(ServletRequest request,
			Class<?> clazz) {
		return bulidBeanMap(request, null, true, clazz);
	}

	/**
	 * 将{@link ServletRequest}
	 * 中的参数构造成一个包含<strong>Bean</strong>属性的<strong>Map</strong> 对象。</br>
	 * <strongstrong>Map</strong>
	 * 中的key对应Bean的属性，如果<strong>Bean</strong>属性是基本封装数据类型
	 * ，则value的类型和<strong>Bean</strong> 的类型是一致的。
	 * <p>
	 * <strong>注意</strong>:会覆盖原有<strong>Map</strong>中的key
	 * 
	 * @param request
	 *            如果为<code>null</code>，则返回一个空的<strong>Map</strong>
	 * @param params
	 *            如果为<code>null</code>，则会创建一个新的<strong>Map</strong>返回给用户，如果不为
	 *            <code>null</code>,则将值插入<strong>Map</strong>，并且会覆盖原有的key
	 * @param emptyToNull
	 *            如果为true,会将空值转化为Null，如果为false，将会把空值插入到MAP中
	 * @param clazz
	 *            Bean的类型,如果为<code>null</code>，则返回一个空的<strong>Map</strong>
	 * @return
	 */
	public static Map<Object, Object> bulidBeanMap(ServletRequest request,
			Map<Object, Object> params, boolean emptyToNull, Class<?> clazz) {
		if (params == null) {
			params = new HashMap<Object, Object>();
		}
		if (request == null) {
			return params;
		}
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			String methodName = method.getName();
			String value = null;
			if (method.getName().matches("get.+")) {
				String prop = methodName.substring(3);
				Class<?> retClazz = method.getReturnType();
				prop = prop.substring(0, 1).toLowerCase() + prop.substring(1);
				value = request.getParameter(prop);
				if (emptyToNull && StringUtil.isBlank(value)) {
					value = null;
				}
				params.put(prop, convertToBaseType(value, retClazz));
			}

		}
		return params;
	}

	/**
	 * 自动封装bean对象
	 * 
	 * @param request
	 *            请求
	 * @param clazz
	 *            bean类型
	 * @return
	 */
	public static <T> T bulidBean(ServletRequest request, Class<T> clazz) {
		T bean = null;
		try {
			bean = clazz.newInstance();
		} catch (InstantiationException e1) {
		} catch (IllegalAccessException e1) {
		}
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			String methodName = method.getName();
			String value = null;
			if (method.getName().matches("set.+")) {
				String prop = methodName.substring(3);
				Class<?> retClazz = method.getParameterTypes()[0];
				prop = prop.substring(0, 1).toLowerCase() + prop.substring(1);
				value = request.getParameter(prop);
				try {
					method.invoke(bean, convertToBaseType(value, retClazz));
				} catch (IllegalArgumentException e) {
				} catch (IllegalAccessException e) {
				} catch (InvocationTargetException e) {
				}
			}

		}
		return bean;
	}

	/**
	 * 将字符串强制转换为指定的基本封装数据类型，如果指定类型不为基本数据类型则不进行转换
	 * 
	 * @param obj
	 *            要转换的值
	 * @param type
	 *            要转换的类型
	 */
	private static Object convertToBaseType(String obj, Class<?> type) {
		if (obj == null) {
			return null;
		}
		if (type.isAssignableFrom(Boolean.class)) {
			return Boolean.parseBoolean(obj.toString());
		} else if (type.isAssignableFrom(Byte.class)) {
			return Byte.parseByte(obj);
		} else if (type.isAssignableFrom(Short.class)) {
			return Short.parseShort(obj.toString());
		} else if (type.isAssignableFrom(Character.class)) {
			if (obj.length() != 1) {
				throw new IllegalArgumentException("错误的参数，" + obj
						+ "不能强制转换为Character类型的数据");
			} else {
				return obj.charAt(0);
			}
		} else if (type.isAssignableFrom(Integer.class)) {
			return Integer.parseInt(obj);
		} else if (type.isAssignableFrom(Float.class)) {
			return Float.parseFloat(obj);
		} else if (type.isAssignableFrom(Long.class)) {
			return Long.parseLong(obj);
		} else if (type.isAssignableFrom(Double.class)) {
			return Double.parseDouble(obj);
		} else {
			return obj;
		}
	}

}
